﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.Application
{
    using System;
    using System.ComponentModel;
    using System.Globalization;
    using System.IO;
    using System.Windows.Forms;

    using Mews.Application.Properties;
    using Mews.Mime;

    /// <summary>The form that displays a single article.</summary>
    internal sealed partial class ShowArticleForm : Form
    {
        private const string RedirectHtml =
            "<html><head><meta http-equiv=\"Refresh\" content=\"0;url={0}\" /></head><body /></html>";

        private static readonly Version windowsMobile65 = new Version("5.2.21234");

        private readonly string tempDirectory;
        private Func<bool> toggleIsBeingWatched;
        private Action<bool> setHasBeenRead;
        private Action followUp;
        private bool isBeingWatched;
        private bool hasBeenRead;
        private Uri startUrl;

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        internal ShowArticleForm(Form owner, string tempDirectory)
        {
            this.tempDirectory = tempDirectory;
            this.InitializeComponent();

            // Apparently this must be set after calling this.InitializeComponent, otherwise the ok button is not
            // visible
            this.Owner = owner;
        }

        internal void ShowDialog(
            Func<bool> newToggleIsBeingWatched,
            Action<bool> newSetHasBeenRead,
            Action<Form, string, string, Message> newFollowUp,
            Action<bool> setHasAttachments,
            Stream content,
            bool newIsBeingWatched)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                this.toggleIsBeingWatched = newToggleIsBeingWatched;
                this.setHasBeenRead = newSetHasBeenRead;
                var message = Message.Parse(content);
                this.followUp =
                    () => newFollowUp(this, "Re: " + message.Subject, TextConverter.ToText(message, 1), message);
                this.SetIsBeingWatched(newIsBeingWatched);
                bool hasAttachments;
                var result = HtmlConverter.ToHtml(message, this.tempDirectory, out hasAttachments);
                setHasAttachments(hasAttachments);
                this.startUrl = result.StartsWith("file://", StringComparison.Ordinal) ? new Uri(result) : null;

                if (this.startUrl == null)
                {
                    this.webBrowser.DocumentText = result;
                }
                else
                {
                    if (Environment.OSVersion.Version < windowsMobile65)
                    {
                        // For devices predating WM6.5, if we set the Url property of WebBrowser then the file is shown
                        // on the default browser registered for html, which might not be IE, which in turn leads to all
                        // kinds of problems. The following redirect ensures that IE is always used.
                        this.webBrowser.DocumentText =
                            string.Format(CultureInfo.InvariantCulture, RedirectHtml, result);
                    }
                    else
                    {
                        // For WM6.5 and later, the system default browser does not seem to have an influence. Strangely
                        // enough, the redirect trick above does not work on these devices.
                        this.webBrowser.Url = this.startUrl;
                    }
                }

                this.webBrowser.Hide();
                this.SetHasBeenRead(true);
                this.ShowDialog();
            }
            catch
            {
                // When this method returns normally the cursor is set to the default cursor in
                // OnWebBrowser_DocumentCompleted.
                Cursor.Current = Cursors.Default;
                throw;
            }
            finally
            {
                content.Dispose();
            }
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>See <see cref="Control.Dispose"/>.</summary>
        protected sealed override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.components != null)
                {
                    this.components.Dispose();
                }
            }

            base.Dispose(disposing);
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private void OnDoneBackMenuItem_Click(object sender, EventArgs e)
        {
            if (this.doneBackMenuItem.Text == Resources.Done)
            {
                this.Close();
            }
            else
            {
                this.webBrowser.GoBack();
            }
        }

        private void OnWatchAllMenuItem_Click(object sender, EventArgs e)
        {
            this.SetIsBeingWatched(this.toggleIsBeingWatched());
        }

        private void OnMarkAsReadMenuItem_Click(object sender, EventArgs e)
        {
            this.SetHasBeenRead(!this.hasBeenRead);
        }

        private void OnWebBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            this.doneBackMenuItem.Text =
                (this.startUrl == null) || (e.Url == this.startUrl) ? Resources.Done : Resources.Back;
        }

        private void OnWebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            Cursor.Current = Cursors.Default;
            this.webBrowser.Show();
        }

        private void OnArticleForm_Closing(object sender, CancelEventArgs e)
        {
            // Resetting these ensures that the article or the generated output is no longer referenced anywhere when
            // the form is closed
            this.webBrowser.DocumentText = string.Empty;
            this.setHasBeenRead = null;
            this.toggleIsBeingWatched = null;

            if (this.startUrl != null)
            {
                try
                {
                    Directory.Delete(this.tempDirectory, true);
                }
                catch (IOException)
                {
                    // Thrown when the application cannot delete the directory due to a file being locked
                    // (probably by a program started by opening an attachment)
                }
            }
        }

        private void SetIsBeingWatched(bool value)
        {
            this.isBeingWatched = value;
            this.watchAllMenuItem.Text = this.isBeingWatched ? Resources.WatchNone : Resources.WatchAll;
        }

        private void SetHasBeenRead(bool value)
        {
            this.hasBeenRead = value;
            this.markAsReadMenuItem.Text = this.hasBeenRead ? Resources.MarkAsUnread : Resources.MarkAsRead;
            this.setHasBeenRead(value);
        }

        private void OnFollowUpMenuItem_Click(object sender, EventArgs e)
        {
            this.followUp();
        }
    }
}